/*
 * vws_thread.cpp
 *
 *  Created on: Sep 20, 2013
 *      Author: vscen
 */

#include "vws_thread.h"

namespace vws {
void vws_thread::RunWorkThread(int iMaxT, void** argv) {
	sem_init(&this->_signal, 0, 0);
	pthread_mutex_init(&_mutex, NULL);

	this->_threadid = new pthread_t[iMaxT];
	this->_taskqueue = new TaskQueue;

	PTHREAD_CONTEXT pTContext = NULL;
	for (int i = 0; i < iMaxT; i++) {
		pTContext = new THREAD_CONTEXT;
		this->_threadctx.push(pTContext);
		pTContext->pWorkQueue = this;
		pTContext->pThreadData = argv == NULL ? NULL : argv[i];
		pthread_attr_t threadAttr;
		pthread_attr_init(&threadAttr);
		pthread_create(&_threadid[i], &threadAttr, WorkThread, pTContext);
		if (this->_threadid[i] == 0) {
			this->_threadmax = i;
			break;
		}
	}
}

void vws_thread::AddTaskThread(InterfaceTP* pTask) {
	this->LockMutex();
	this->_taskqueue->push(pTask);
	this->UnlockMutex();
	this->PostSem();
}

void vws_thread::DestroyThread() {
	sem_destroy(&_signal);
	pthread_mutex_destroy(&_mutex);
	for (int i = 0; i < this->_threadmax; i++) {
		pthread_join(this->_threadid[i], NULL);
	}
	while (this->_threadctx.size()) {
		PTHREAD_CONTEXT pdel = this->_threadctx.front();
		this->_threadctx.pop();
		delete pdel;
	}
	delete[] this->_threadid;
	delete this->_taskqueue;
}

void* vws_thread::WorkThread(void* arg) {
	PTHREAD_CONTEXT pThreadContext = static_cast<PTHREAD_CONTEXT> (arg);
	vws_thread* pManager = pThreadContext->pWorkQueue;
	void* pArg = pThreadContext->pThreadData;
	for (;;) {
		int iwait = pManager->WaitSem();
		if (iwait == 0) {
			InterfaceTP* pTask = pManager->SunTaskThread();
			pTask->DoThread(pArg);
		}
	}
	delete pThreadContext;
	return NULL;
}

InterfaceTP* vws_thread::SunTaskThread() {
	this->LockMutex();
	InterfaceTP* pWorkItem = this->_taskqueue->front();
	this->_taskqueue->pop();
	this->UnlockMutex();
	assert(pWorkItem != NULL);
	return pWorkItem;
}

int vws_thread::WaitSem() {
	return sem_wait(&_signal);
}

int vws_thread::PostSem() {
	return sem_post(&_signal);
}

int vws_thread::LockMutex() {
	int n = pthread_mutex_lock(&_mutex);
	return n;
}

int vws_thread::UnlockMutex() {
	return pthread_mutex_unlock(&_mutex);
}
}
